// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.CodeAnalysis;
using SourceGenerators;

namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
    public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerator
    {
        private sealed partial class Emitter
        {
            private readonly InterceptorInfo _interceptorInfo;
            private readonly BindingHelperInfo _bindingHelperInfo;
            private readonly TypeIndex _typeIndex;
            private readonly bool _emitEnumParseMethod;
            private readonly bool _emitGenericParseEnum;
            private readonly bool _emitNotNullIfNotNull;
            private readonly bool _emitThrowIfNullMethod;

            private readonly SourceWriter _writer = new();

            public Emitter(SourceGenerationSpec sourceGenSpec)
            {
                _interceptorInfo = sourceGenSpec.InterceptorInfo;
                _bindingHelperInfo = sourceGenSpec.BindingHelperInfo;
                _typeIndex = new TypeIndex(sourceGenSpec.ConfigTypes);
                _emitEnumParseMethod = sourceGenSpec.EmitEnumParseMethod;
                _emitGenericParseEnum = sourceGenSpec.EmitGenericParseEnum;
                _emitNotNullIfNotNull = sourceGenSpec.EmitNotNullIfNotNull;
                _emitThrowIfNullMethod = sourceGenSpec.EmitThrowIfNullMethod;
            }

            public void Emit(SourceProductionContext context)
            {
                if (!ShouldEmitMethods(MethodsToGen.Any))
                {
                    return;
                }

                _writer.WriteLine("""
                    // <auto-generated/>

                    #nullable enable annotations
                    #nullable disable warnings

                    // Suppress warnings about [Obsolete] member usage in generated code.
                    #pragma warning disable CS0612, CS0618
                    """);

                EmitInterceptsLocationAttrDecl();

                EmitStartBlock($"namespace {ProjectName}");
                EmitUsingStatements();

                _writer.WriteLine();
                EmitStartBlock($$"""
                    {{Expression.GeneratedCodeAnnotation}}
                    file static class {{Identifier.BindingExtensions}}
                    """);
                EmitBindingExtensions_IConfiguration();
                EmitBindingExtensions_OptionsBuilder();
                EmitBindingExtensions_IServiceCollection();
                EmitCoreBindingHelpers();
                EmitEndBlock(); // BindingExtensions class

                EmitEndBlock(); // Binding namespace.

                context.AddSource($"{Identifier.BindingExtensions}.g.cs", _writer.ToSourceText());
            }

            private void EmitInterceptsLocationAttrDecl()
            {
                _writer.WriteLine();

                string arguments = ConfigurationBindingGenerator.InterceptorVersion == 0 ?
                    "string filePath, int line, int column" :
                    "int version, string data";

                _writer.WriteLine($$"""
                namespace System.Runtime.CompilerServices
                {
                    using System;
                    using System.CodeDom.Compiler;

                    {{Expression.GeneratedCodeAnnotation}}
                    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
                    file sealed class InterceptsLocationAttribute : Attribute
                    {
                        public InterceptsLocationAttribute({{arguments}})
                        {
                        }
                    }
                }
                """);

                _writer.WriteLine();
            }

            private void EmitUsingStatements()
            {
                foreach (string @namespace in _bindingHelperInfo.Namespaces)
                {
                    _writer.WriteLine($"using {@namespace};");
                }
            }
        }
    }
}
